using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEngine;

public static class StringExtensions
{
    public static string ToPascalCase(this string s)
    {
        string sample = string.Join("", s?.Select(c => char.IsLetterOrDigit(c) ? c.ToString().ToLower() : "_").ToArray());

        var arr = sample?
            .Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries)
            .Select(s => $"{s.Substring(0, 1).ToUpper()}{s.Substring(1)}");

        sample = string.Join("", arr);

        return sample;
    }

    public static string ToCamelCase(this string s)
    {
        if (string.IsNullOrEmpty(s))
        {
            return string.Empty;
        }

        var sample = s.ToPascalCase();

        return $"{sample.FirstOrDefault().ToString().ToLower()}{sample.Substring(1)}";
    }
}

public class BuildScript
{
    private static readonly string _projectName;
    private static readonly string _outputDirectory;
    private static readonly string _applicationIdentifier;
    private static readonly string _versionNumber;
    private static readonly string _buildNumber;
    private static readonly string _androidKeyStorePath;
    private static readonly string _androidKeyStorePassword;
    private static readonly string _androidKeyAlias;
    private static readonly string _androidKeyAliasPassword;

    static BuildScript()
    {
        _projectName = Environment.GetEnvironmentVariable("UNITY_PROJECT_NAME") ?? "Unity";
        _outputDirectory = Environment.GetEnvironmentVariable("UNITY_OUTPUT_DIRECTORY") ?? Application.persistentDataPath;
        _versionNumber = Environment.GetEnvironmentVariable("UNITY_PROJECT_VERSION") ?? "0.1.0";
        _buildNumber = Environment.GetEnvironmentVariable("UNITY_PROJECT_BUILD_NUMBER") ?? "1";
        _androidKeyStorePath = Environment.GetEnvironmentVariable("UNITY_ANDROID_KEYSTORE");
        _androidKeyStorePassword = Environment.GetEnvironmentVariable("UNITY_ANDROID_KEYSTORE_PASSWORD");
        _androidKeyAlias = Environment.GetEnvironmentVariable("UNITY_ANDROID_KEY_ALIAS") ?? "key0";
        _androidKeyAliasPassword = Environment.GetEnvironmentVariable("UNITY_ANDROID_KEY_ALIAS_PASSWORD");
        _applicationIdentifier = string.Format("com.optoma.{0}", _projectName.ToCamelCase());

        Console.WriteLine($"-- Application Identifier:\t{_applicationIdentifier}");
        Console.WriteLine($"-- Project Name:\t{_projectName}");
        Console.WriteLine($"-- Output Directory:\t{_outputDirectory}");

        PlayerSettings.productName = _projectName;
        PlayerSettings.bundleVersion = $"{_versionNumber}.{_buildNumber}";
    }

    static void StandaloneWindows64()
    {
        string locationPathName = Path.Combine(_outputDirectory, "win-x64", $"{_projectName}.exe");
        string path = Path.GetDirectoryName(locationPathName);
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Standalone, _applicationIdentifier);

        BuildPlayer(locationPathName, BuildTarget.StandaloneWindows64);
    }

    static void Android()
    {
#if UNITY_2018_3_OR_NEWER
        var filename = $"{_projectName}.{(EditorUserBuildSettings.buildAppBundle ? "aab" : "apk")}";
#else
        var filename = $"{_projectName}.apk";
#endif

        string locationPathName = Path.Combine(_outputDirectory, "android", filename);
        string path = Path.GetDirectoryName(locationPathName);
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        PlayerSettings.SetApplicationIdentifier(BuildTargetGroup.Android, _applicationIdentifier);
        HandleAndroidKeystore();

        BuildPlayer(locationPathName, BuildTarget.Android);
    }

    static string[] GetScenes()
    {
        return (
            from scene in EditorBuildSettings.scenes
            where scene.enabled
            where !string.IsNullOrEmpty(scene.path)
            select scene.path
        ).ToArray();
    }

    static void BuildPlayer(string locationPathName, BuildTarget target, BuildOptions options = BuildOptions.None)
    {
        _ = locationPathName ?? throw new ArgumentNullException(nameof(locationPathName));

        BuildReport report = BuildPipeline.BuildPlayer(GetScenes(), locationPathName, target, options);
        if (report.summary.result == BuildResult.Succeeded)
        {
            Console.WriteLine($"Build completed with a result of 'Succeeded' in {report.summary.totalTime} seconds");
            EditorApplication.Exit(0);
        }
        else if (report.summary.result == BuildResult.Failed)
        {
            Console.WriteLine($"Failed to build player\nReport:\n{report.summary.totalErrors}");
            EditorApplication.Exit(1);
        }
    }

    static void HandleAndroidKeystore()
    {
#if UNITY_2019_1_OR_NEWER
        PlayerSettings.Android.useCustomKeystore = false;
#endif

        if (string.IsNullOrEmpty(_androidKeyStorePath))
            throw new NullReferenceException("Failed get get \"UNITY_ANDROID_KEYSTORE\" from environment variable");

        if (!File.Exists(_androidKeyStorePath))
            throw new FileNotFoundException("The keystore file does not found");

        PlayerSettings.Android.keystoreName = _androidKeyStorePath.Replace('\\', '/');
#if UNITY_2019_1_OR_NEWER
        PlayerSettings.Android.useCustomKeystore = true;
#endif
        PlayerSettings.Android.keystorePass = _androidKeyStorePassword;
        PlayerSettings.Android.keyaliasName = _androidKeyAlias;
        PlayerSettings.Android.keyaliasPass = _androidKeyAliasPassword;

        if (int.TryParse(_buildNumber, out var versionCode))
            PlayerSettings.Android.bundleVersionCode = versionCode;
    }
}
